import json
from typing import List, Dict, Any

from langchain_core.tools import tool

from config.database import get_db_session
from config.logging_config import get_logger
from mcp_tools.mcpFactory import MCPFactory
from pojo.ai_web_mcp_tools_model import AIWebMCPToolsModel
from tools.ToolManager import ToolManager, SingleToolConfig

logger = get_logger(__name__)


@tool
def call_mcp_tool(mcp_service: str, tool_name: str, parameters: str = "{}") -> str:
    """
    调用指定MCP服务的工具方法。
    
    参数:
        mcp_service: MCP服务名称或ID
        tool_name: 要调用的工具名称
        parameters: 工具参数，JSON字符串格式（如 '{{"key": "value"}}'）
    
    返回:
        MCP工具执行结果的字符串表示
    """
    try:
        logger.info(f"🔧 开始调用MCP工具: {mcp_service}.{tool_name}")

        # 解析参数
        try:
            tool_params = json.loads(parameters) if parameters else {}
        except json.JSONDecodeError as e:
            error_msg = f"参数格式错误，必须是有效的JSON字符串: {str(e)}"
            logger.error(error_msg)
            return f"❌ 调用失败: {error_msg}"

        # 获取数据库会话
        db = next(get_db_session())
        try:
            # 查找MCP服务
            if mcp_service.isdigit():
                mcp_tool = db.query(AIWebMCPToolsModel).filter(
                    AIWebMCPToolsModel.id == mcp_service,
                    AIWebMCPToolsModel.status == 1
                ).first()
            else:
                mcp_tool = db.query(AIWebMCPToolsModel).filter(
                    AIWebMCPToolsModel.mcp_name == mcp_service,
                    AIWebMCPToolsModel.status == 1
                ).first()

            if not mcp_tool:
                error_msg = f"未找到MCP服务: {mcp_service}"
                logger.error(error_msg)
                return f"❌ 调用失败: {error_msg}"

            # 使用新的异步MCP调用方式
            logger.info(f"📡 调用MCP工具: {mcp_service}.{tool_name}，参数: {tool_params}")

            import asyncio

            # 根据当前事件循环状态选择执行方式
            try:
                loop = asyncio.get_event_loop()
                if loop.is_running():
                    # 在已有事件循环中，使用run_in_executor
                    import concurrent.futures
                    with concurrent.futures.ThreadPoolExecutor() as executor:
                        future = executor.submit(
                            lambda: asyncio.run(
                                MCPFactory.call_mcp_tool(mcp_tool.mcp_name, tool_name, json.dumps(tool_params)))
                        )
                        result = future.result(timeout=30)
                else:
                    # 没有运行的事件循环，直接运行
                    result = loop.run_until_complete(
                        MCPFactory.call_mcp_tool(mcp_tool.mcp_name, tool_name, json.dumps(tool_params)))
            except RuntimeError:
                # 没有事件循环，创建新的
                result = asyncio.run(MCPFactory.call_mcp_tool(mcp_tool.mcp_name, tool_name, json.dumps(tool_params)))

            logger.info(f"✅ MCP工具调用成功: {mcp_service}.{tool_name}")
            return result
        finally:
            db.close()

    except Exception as e:
        error_msg = f"MCP工具调用异常: {str(e)}"
        logger.error(error_msg, exc_info=True)
        return f"❌ 调用失败: {error_msg}"


@tool
def list_mcp_services() -> str:
    """
    列出所有可用的MCP服务和其工具。
    
    返回:
        可用MCP服务和工具的列表信息
    """
    try:
        logger.info("📋 获取可用MCP服务列表")

        # 使用mcp_client获取连接状态和工具信息
        from mcp_tools.mcpClient import mcp_client
        import asyncio

        # 获取连接的服务器
        connected_servers = mcp_client.get_connected_servers()

        if not connected_servers:
            return "📝 当前没有连接的MCP服务"

        services_info = []
        services_info.append(f"📡 已连接的MCP服务 ({len(connected_servers)} 个):")
        services_info.append("")

        # 异步获取工具信息
        try:
            loop = asyncio.get_event_loop()
            if loop.is_running():
                # 在已有事件循环中，使用run_in_executor
                import concurrent.futures
                with concurrent.futures.ThreadPoolExecutor() as executor:
                    future = executor.submit(
                        lambda: asyncio.run(mcp_client.get_tools())
                    )
                    all_tools = future.result(timeout=30)
            else:
                all_tools = loop.run_until_complete(mcp_client.get_tools())
        except RuntimeError:
            all_tools = asyncio.run(mcp_client.get_tools())

        # 按服务器分组工具
        tools_by_server = {}
        for tool in all_tools:
            server_name = tool.server_name
            if server_name not in tools_by_server:
                tools_by_server[server_name] = []
            tools_by_server[server_name].append(tool)

        for i, server_name in enumerate(connected_servers, 1):
            services_info.append(f"{i}. 🔧 {server_name}")

            # 获取该服务器的工具列表
            server_tools = tools_by_server.get(server_name, [])
            if server_tools:
                services_info.append(f"   📦 可用工具 ({len(server_tools)} 个):")
                for j, tool in enumerate(server_tools, 1):
                    tool_name = tool.name
                    tool_desc = tool.description or '无描述'
                    services_info.append(f"      {j}. {tool_name}: {tool_desc}")
            else:
                services_info.append("   ⚠️ 无可用工具")

            services_info.append("")

        # 添加使用说明
        services_info.append("💡 使用方法:")
        services_info.append("   调用 call_mcp_tool 工具，传入:")
        services_info.append("   - mcp_service: 服务名称或ID")
        services_info.append("   - tool_name: 工具名称")
        services_info.append("   - parameters: JSON格式的参数")

        result = "\n".join(services_info)
        logger.info("✅ 成功获取MCP服务列表")
        return result

    except Exception as e:
        error_msg = f"获取MCP服务列表失败: {str(e)}"
        logger.error(error_msg, exc_info=True)
        return f"❌ 获取失败: {error_msg}"


class MCPCallingToolManager(ToolManager):
    """MCP调用工具管理器"""

    @property
    def category_name(self) -> str:
        return "MCP工具调用器"

    @property
    def category_code(self) -> str:
        return "mcp_calling"

    @property
    def category_description(self) -> str:
        return "用于调用外部MCP (Model Context Protocol) 服务的工具集，可以连接和调用各种MCP服务器提供的功能"

    def get_tool_configs(self) -> List[Dict[str, Any]]:
        # MCP工具调用器
        mcp_call_tool = SingleToolConfig(
            tool_id=1,
            tool_name="call_mcp_tool",
            description="调用指定MCP服务的工具方法，用于执行外部MCP服务器提供的功能",
            is_enabled=True
        )

        mcp_call_tool.add_parameter(
            param_name="mcp_service",
            param_type="string",
            description="MCP服务名称或ID（如：'高德地图MCP' 或 '2'）",
            is_required=True
        )

        mcp_call_tool.add_parameter(
            param_name="tool_name",
            param_type="string",
            description="要调用的工具名称（如：'maps_direction_driving'）",
            is_required=True
        )

        mcp_call_tool.add_parameter(
            param_name="parameters",
            param_type="string",
            description="工具参数，JSON字符串格式（如：'{{\"origin\": \"北京\", \"destination\": \"上海\"}}'）",
            default_value="{}",
            is_required=False
        )

        # MCP服务列表查询器
        mcp_list_tool = SingleToolConfig(
            tool_id=2,
            tool_name="list_mcp_services",
            description="列出所有可用的MCP服务和其提供的工具，帮助了解可以调用哪些外部功能",
            is_enabled=True
        )

        return [mcp_call_tool.to_dict(), mcp_list_tool.to_dict()]

    def get_langchain_tools(self):
        """返回多个工具的列表"""
        return [call_mcp_tool, list_mcp_services]

    def get_langchain_tool(self):
        """返回工具列表（为了与ToolFactory兼容）"""
        return [call_mcp_tool, list_mcp_services]


# 创建全局实例
mcp_calling_tool_manager = MCPCallingToolManager()
